#include "Aht20.h"

AHT20_Write_Data_callback wd_cb = NULL;

AHT20_init_t g_aht20 = {0};

#define AHT20_delay_ms(x)   g_aht20.delay_ms_cb(x)

/**
  * @brief  读AHT20 设备状态字
  * @param  void
  * @retval uint8_t 设备状态字
  */
static uint8_t AHT20_ReadStatusCmd(void)
{
    uint8_t tmp[1];
    g_aht20.rd_cb(g_aht20.iic_addr, AHT20_STATUS_REG, tmp, 1);
    return tmp[0];
}

/**
  * @brief  读AHT20 设备状态字 中的Bit3: 校准使能位
  * @param  void
  * @retval uint8_t 校准使能位：1 - 已校准; 0 - 未校准
  */
static uint8_t AHT20_ReadCalEnableCmd(void)
{
    uint8_t tmp;
    tmp = AHT20_ReadStatusCmd();
    return (tmp >> 3) & 0x01;
}

/**
  * @brief  读AHT20 设备状态字 中的Bit7: 忙标志
  * @param  void
  * @retval uint8_t 忙标志：1 - 设备忙; 0 - 设备空闲
  */
static uint8_t AHT20_ReadBusyCmd(void)
{
    uint8_t tmp;
    tmp = AHT20_ReadStatusCmd();
    return (tmp>>7)&0x01;
}

/**
  * @brief  AHT20 发送芯片初始化命令
  * @param  void
  * @retval void
  */
static void AHT20_IcInitCmd(void)
{
    uint8_t tmp[2];
    tmp[0] = 0x08;
    tmp[1] = 0x00;
    g_aht20.wd_cb(g_aht20.iic_addr, AHT20_INIT_REG, tmp, 2);
}

/**
  * @brief  AHT20 软复位命令
  * @param  void
  * @retval void
  */
static void AHT20_SoftResetCmd(void)
{
    uint8_t tmp[1];
    g_aht20.wd_cb(g_aht20.iic_addr, AHT20_SoftReset, tmp, 0);
}

/**
  * @brief  AHT20 触发测量命令
  * @param  void
  * @retval void
  */
void AHT20_TrigMeasureCmd(void)
{
    uint8_t tmp[2];
    tmp[0] = 0x33;
    tmp[1] = 0x00;
    g_aht20.wd_cb(g_aht20.iic_addr, AHT20_TrigMeasure_REG, tmp, 2);
}

uint8_t AHT_Init(AHT20_init_t init_conf)   //初始化AHT10
{
    if (init_conf.delay_ms_cb == NULL ||
        init_conf.wd_cb == NULL ||
        init_conf.rd_cb == NULL) {
        printf("AHT_Init error: callback function can't be NULL\n");
        return 0;
    }

    g_aht20.iic_addr = init_conf.iic_addr ? init_conf.iic_addr : ATH20_SLAVE_ADDRESS;
    g_aht20.wd_cb = init_conf.wd_cb;
    g_aht20.rd_cb = init_conf.rd_cb;
    g_aht20.delay_ms_cb = init_conf.delay_ms_cb;

    uint8_t tmp = AHT20_ReadStatusCmd();

    if (tmp == 0xff) {
        printf("Not found device, status:0x%x\n", tmp);
        return -1; //器件不存在
    }

    uint8_t rcnt = 2+1;//软复位命令 重试次数，2次
    uint8_t icnt = 2+1;//初始化命令 重试次数，2次

    while(--rcnt)
    {
        icnt = 2+1;
        
        AHT20_delay_ms(40);//上电后要等待40ms
        // 读取温湿度之前，首先检查[校准使能位]是否为1
        while((!AHT20_ReadCalEnableCmd()) && (--icnt))// 2次重试机会
        {
            // 如果不为1，要发送初始化命令
            AHT20_IcInitCmd();
            AHT20_delay_ms(10);//这个时间不确定，手册没讲
        }
        
        if(icnt)//[校准使能位]为1,校准正常
            break;//退出rcnt循环
        else//[校准使能位]为0,校准错误
        {
            AHT20_SoftResetCmd();//软复位AHT20器件，重试
            AHT20_delay_ms(20);//这个时间不确定，手册没讲
        }
    }

    return rcnt ? 0 : -1;

//    return 0;// AHT20设备初始化正常
//    return -1;// AHT20设备初始化失败
}


/**
  * @brief  AHT20 设备读取 相对湿度和温度（原始数据20Bit），直接触发转换并阻塞等待读取
  * @param  rd_data ：读取到的数据
  * @retval uint8_t：0:读取数据正常; -1:读取设备失败
  */
uint8_t AHT20_ReadHT(AHT20_data_t *rd_data)
{
    uint8_t cnt=3+1;//忙标志 重试次数，3次
    uint8_t tmp[6];
    uint32_t RetuData = 0;
    
    // 发送触发测量命令
    AHT20_TrigMeasureCmd();
    
    do{
        AHT20_delay_ms(80);//等待75ms待测量完成，忙标志Bit7为0
    }while(AHT20_ReadBusyCmd() && (--cnt));//重试3次

    if (cnt == 0) //设备忙，返回读取失败
        return -1;

    AHT20_delay_ms(5);
    // 读温湿度数据
    g_aht20.rd_cb(g_aht20.iic_addr, AHT20_STATUS_REG, tmp, 6);
    // 计算相对湿度RH。原始值，未计算为标准单位%。
    RetuData = 0;
    RetuData = (RetuData|tmp[1]) << 8;
    RetuData = (RetuData|tmp[2]) << 8;
    RetuData = (RetuData|tmp[3]);
    RetuData = RetuData >> 4;
    rd_data->RH = (double)RetuData * 100 / 1048576;

    // 计算温度T。原始值，未计算为标准单位°C。
    RetuData = 0;
    RetuData = (RetuData|tmp[3]) << 8;
    RetuData = (RetuData|tmp[4]) << 8;
    RetuData = (RetuData|tmp[5]);
    RetuData = RetuData&0xfffff;
    rd_data->Temp = (double)RetuData *200 / 1048576 -50;

    //限幅,RH=0~100%; Temp=-40~85°C
    return (rd_data->RH >=0)&&(rd_data->RH <=100) && (rd_data->Temp >=-40)&&(rd_data->Temp <=85) ? 0 : -2;

//    return 0;//测量数据正常
//    return -1;//测量数据超出范围，错误
}

/**
  * @brief  AHT20 设备读取 相对湿度和温度（原始数据20Bit），判断转换是否完成，如果未完成则退出
  * @param  rd_data ：读取到的数据
  * @retval uint8_t：0:读取数据正常; -1:读取设备失败
  */
uint8_t AHT20_ReadHT_noblock(AHT20_data_t *rd_data)
{
    uint8_t tmp[6];
    uint32_t RetuData = 0;

    if (AHT20_ReadBusyCmd())
        return -1;  //设备忙，返回读取失败

    // 读温湿度数据
    g_aht20.rd_cb(g_aht20.iic_addr, AHT20_STATUS_REG, tmp, 6);
    // 计算相对湿度RH。原始值，未计算为标准单位%。
    RetuData = 0;
    RetuData = (RetuData|tmp[1]) << 8;
    RetuData = (RetuData|tmp[2]) << 8;
    RetuData = (RetuData|tmp[3]);
    RetuData = RetuData >> 4;
    rd_data->RH = (double)RetuData * 100 / 1048576;

    // 计算温度T。原始值，未计算为标准单位°C。
    RetuData = 0;
    RetuData = (RetuData|tmp[3]) << 8;
    RetuData = (RetuData|tmp[4]) << 8;
    RetuData = (RetuData|tmp[5]);
    RetuData = RetuData&0xfffff;
    rd_data->Temp = (double)RetuData *200 / 1048576 -50;

    //限幅,RH=0~100%; Temp=-40~85°C
    return (rd_data->RH >=0)&&(rd_data->RH <=100) && (rd_data->Temp >=-40)&&(rd_data->Temp <=85) ? 0 : -2;

//    return 0;//测量数据正常
//    return -1;//测量数据超出范围，错误
}

